/*
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *      
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *      
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *      MA 02110-1301, USA.
 */


struct SSong
{
	bool Repeat;
	char Song[256];
	GstElement *Play;
	GMainLoop *Loop;
	bool Playing;
	bool Closed;
};
bool Inited = false;
SSong Songs[64];
char *workdir;
static gboolean
my_bus_callback (GstBus     *bus,
				 GstMessage *message,
				 gpointer    data)
{
	int Variable = *(int*)data;
	
	switch (GST_MESSAGE_TYPE (message)) {
		case GST_MESSAGE_ERROR: {
			GError *err;
			gchar *debug;
			
			gst_message_parse_error (message, &err, &debug);
			g_print ("Error: %s\n", err->message);
			g_error_free (err);
			g_free (debug);
			
			g_main_loop_quit (Songs[Variable].Loop);
			break;
		}
		case GST_MESSAGE_EOS:
			/* end-of-stream */
			g_main_loop_quit (Songs[Variable].Loop);
			return false; // Don't want to hear this bus callback anymore
			break;
		default:
			/* unhandled message */
			break;
	}
	
	/* we want to be notified again the next time there is a message
	 * on the bus, so returning TRUE (FALSE means we want to stop watching
	 * for messages on the bus and our callback should not be called again)
	 */
	return TRUE;
}


bool InitMusic(int argc, char * const argv[]) // Init Sound System
{
	/* init GStreamer */
	gst_init (&argc, (char***)&argv);
	for(int a = 0;a < 64;a++)
	{
		Songs[a].Repeat = false;
		strcpy(Songs[a].Song, "");
		Songs[a].Play = NULL;
		Songs[a].Loop = NULL;
		Songs[a].Playing = false;
		Songs[a].Closed = true;
	}
	workdir = getcwd(NULL,0);
	Inited = true;
	return true;
}
void ShutdownMusic() // Shut it down!
{
	if(Inited)
	{
		for(int a = 0;a < 64;a++)
			if(Songs[a].Closed == false)
				CloseSong(a);
		//gst_deinit(); // This function makes us lock up
	}
}
void MusicVolume(int Volume)
{
	//TODO
}
int OpenSong(std::string filename, bool repeat)
{
	return OpenSong(filename.c_str(), repeat);
}
int OpenSong(const char *filename, bool repeat)
{
	int Variable;
	char tempname[256];
	sprintf(tempname, "file://%s/Data/%s", workdir, filename);
	for(Variable = 0;Variable < 64;Variable++)
		if(Songs[Variable].Playing == false && Songs[Variable].Closed == true)
			break;
	/* set up */
	strcpy(Songs[Variable].Song, tempname);
	
	Songs[Variable].Loop = g_main_loop_new (NULL, FALSE);
	Songs[Variable].Play = gst_element_factory_make ("playbin", "play");
	g_object_set (G_OBJECT (Songs[Variable].Play), "uri", Songs[Variable].Song, NULL);
	GstBus *bus;
	bus = gst_pipeline_get_bus (GST_PIPELINE (Songs[Variable].Play));
	gst_bus_add_watch (bus, my_bus_callback, (void*)&Variable);
	gst_object_unref (bus);
	
	Songs[Variable].Repeat = repeat;
	Songs[Variable].Playing = false;
	Songs[Variable].Closed = false;
	return Variable;
}
void* PlaySong_Thread(void *pointer)
{
	int Variable = *(int*)pointer;
	Songs[Variable].Playing = true;
	do
	{
		// Todo: Put checks in here, to make sure it won't crash
		gst_element_set_state (Songs[Variable].Play, GST_STATE_PLAYING);
		g_main_loop_run(Songs[Variable].Loop);
		gst_element_set_state (Songs[Variable].Play, GST_STATE_NULL);
	}while(Songs[Variable].Repeat);
	Songs[Variable].Playing = false;
	return 0;
}
void PlaySong(int Variable)
{
	/* now run */
	pthread_t thread;
	pthread_create(&thread, NULL, PlaySong_Thread, (void *)&Variable);
}
bool IsPlaying(int Variable)
{
	return Songs[Variable].Playing;
}
void StopSong(int Variable)
{
	if(g_main_loop_is_running(Songs[Variable].Loop))
		g_main_loop_quit(Songs[Variable].Loop);
	gst_element_set_state (Songs[Variable].Play, GST_STATE_NULL);
}
void PauseSong(int Variable)
{
	GstState state, pending;
	gst_element_get_state(Songs[Variable].Play, &state, &pending, GST_CLOCK_TIME_NONE);
    
	if(state == GST_STATE_PLAYING)
	{
		gst_element_set_state (Songs[Variable].Play, GST_STATE_PAUSED);
		Songs[Variable].Playing = false;
	}
    else if(state == GST_STATE_PAUSED)
    {
		gst_element_set_state (Songs[Variable].Play, GST_STATE_PLAYING);
		Songs[Variable].Playing = true;
	}
}
void SongVolume(int Variable, int Volume)
{
	//TODO
}
void CloseSong(int Variable)
{
	/* also clean up */
	if(g_main_loop_is_running(Songs[Variable].Loop))
		g_main_loop_quit(Songs[Variable].Loop);
	gst_element_set_state (Songs[Variable].Play, GST_STATE_NULL);
	gst_object_unref (GST_OBJECT (Songs[Variable].Play));
	Songs[Variable].Closed = true;
	Songs[Variable].Playing = false;
}